package com.eight.paper.admin.util.pdf;

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.toolbox.plugins.watermarker.Watermarker;
import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.util.Map;

/**
 * @desc: freemarker模板引擎生成pdf
 * @author: eight
 */
@Slf4j
public class PdfFreemarkerUtils extends PdfWrapper {

    /**
     * 生成pdf文件字节数组
     *
     * @param templateName 模板文件名
     * @param dataModel    数据
     * @throws DocumentException
     * @throws IOException
     * @throws TemplateException
     */
    public static byte[] export(String templateName, Map<String, Object> dataModel) throws DocumentException, IOException, TemplateException {
        return export(initConfiguration(), templateName, dataModel);
    }

    /**
     * 生成pdf文件字节数组
     *
     * @param templateName 模板文件名
     * @param dataModel    数据
     * @throws DocumentException
     * @throws IOException
     * @throws TemplateException
     */
    public static byte[] export(String templateDirPath, String templateName, Map<String, Object> dataModel) throws DocumentException, IOException, TemplateException {
        return export(initConfiguration(templateDirPath), templateName, dataModel);
    }

    /**
     * 生成pdf文件字节数组
     *
     * @param templateName 模板文件名
     * @param dataModel    数据
     * @throws DocumentException
     * @throws IOException
     * @throws TemplateException
     */
    public static byte[] export(Configuration config, String templateName, Map<String, Object> dataModel) throws DocumentException, IOException, TemplateException {
        // 解析模板
        String content = parseFreemarker(config, templateName, dataModel);
        if (log.isDebugEnabled()) {
            log.debug("after freemarker parse content:\n{}", content);
        }
        ITextRenderer renderer = new ITextRenderer();
        ITextFontResolver fontResolver = renderer.getFontResolver();
        BaseFont baseFont = BaseFont.createFont(getFontPath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        fontResolver.addFont(getFontPath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        // 解决图片的相对路径问题
        String baseImgDir = getBaseImgDir();
        if (StringUtils.hasText(baseImgDir)) {
            renderer.getSharedContext().setBaseURL(baseImgDir);
        }
        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            renderer.setDocumentFromString(content);
            renderer.layout();
            renderer.createPDF(os);

            /**
             * ITextRenderer只是对css做渲染，水印需要在pdf文件流生成后处理
             */
            byte[] bytes = os.toByteArray();
            if (getPdfWatermark() != null) {
                bytes = setWatermark(baseFont, bytes);
            }
            return bytes;
        } finally {
            renderer.finishPDF();
        }
    }

    /**
     * 设置水印
     *
     * @param baseFont
     * @param bytes
     * @return
     * @throws IOException
     */
    private static byte[] setWatermark(BaseFont baseFont, byte[] bytes) throws IOException {
        PdfWatermark pdfWatermark = getPdfWatermark();
        byte[] pdfBytesWithWaterMark =
                new byte[0];
        try {
            pdfBytesWithWaterMark = new Watermarker(bytes, pdfWatermark.getText(), pdfWatermark.getFontsize(), pdfWatermark.getOpacity())
                    .withColor(pdfWatermark.getFontColor())
                    .withFont(baseFont)
                    .write();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return pdfBytesWithWaterMark;
    }

    /**
     * 解析 FreeMarker 模板
     *
     * @param freemarker
     * @param dataModel
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    private static String parseFreemarker(Configuration cfg, String freemarker, Map<String, Object> dataModel) throws IOException, TemplateException {
        Template temp = cfg.getTemplate(freemarker);
        try (Writer out = new StringWriter()) {
            temp.process(dataModel, out);
            return out.toString();
        }
    }

    /**
     * 初始化 FreeMarker 配置
     *
     * @return
     * @throws IOException
     */
    private static Configuration initConfiguration() {
        Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        cfg.setClassForTemplateLoading(PdfFreemarkerUtils.class, getTemplateDirPath());
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        cfg.setWrapUncheckedExceptions(true);
        return cfg;
    }

    /**
     * 初始化 FreeMarker 配置
     *
     * @return
     * @throws IOException
     */
    private static Configuration initConfiguration(String templateDirPath) throws IOException {
        Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        if (StringUtils.isEmpty(templateDirPath)) {
            cfg.setClassForTemplateLoading(PdfFreemarkerUtils.class, getTemplateDirPath());
        } else {
            FileTemplateLoader fileTemplateLoader = new FileTemplateLoader(new File(templateDirPath));
            cfg.setTemplateLoader(fileTemplateLoader);
        }
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        cfg.setWrapUncheckedExceptions(true);
        return cfg;
    }
}
